@file:Suppress("UNCHECKED_CAST")

package com.gitee.wsl.struct.grammar.parser.combinator

import com.gitee.wsl.base.Tuple10
import com.gitee.wsl.base.Tuple11
import com.gitee.wsl.base.Tuple12
import com.gitee.wsl.base.Tuple13
import com.gitee.wsl.base.Tuple14
import com.gitee.wsl.base.Tuple15
import com.gitee.wsl.base.Tuple16
import com.gitee.wsl.base.Tuple2
import com.gitee.wsl.base.Tuple3
import com.gitee.wsl.base.Tuple4
import com.gitee.wsl.base.Tuple5
import com.gitee.wsl.base.Tuple6
import com.gitee.wsl.base.Tuple7
import com.gitee.wsl.base.Tuple8
import com.gitee.wsl.base.Tuple9
import com.gitee.wsl.struct.grammar.parser.Parser
import kotlin.jvm.JvmName


/**
 * Creates a parser from a pair of parsers, returning a pair of their results.
 */
@JvmName("parserAndParser")
infix fun <A, B> Parser<A>.and(p: Parser<B>): Parser<Tuple2<A, B>> =
    retuple(this, p) {
        Tuple2(it[0] as A, it[1] as B)
    }

/**
 * Creates a parser from a pair of parsers, returning a pair of their results.
 */
@JvmName("parserTimesParser")
operator fun <A, B> Parser<A>.times(p: Parser<B>): Parser<Tuple2<A, B>> = this and p


/**
 * Creates a parser that runs both parsers, but only returns the result of the first parser.
 */
@JvmName("parserAndIgnored")
infix fun <A> Parser<A>.and(p: Parser<Unit>): Parser<A> =
    retuple(this, ignored(p)) {
        it[0] as A
    }

/**
 * Creates a parser that runs both parsers, but only returns the result of the first parser.
 */
@JvmName("parserTimesIgnored")
operator fun <A> Parser<A>.times(p: Parser<Unit>): Parser<A> = this and p

/**
 * Creates a parser that ignores the result of the first parser and returns the result of the second parser.
 */
@JvmName("ignoredAndParser")
infix fun <B> Parser<Unit>.and(p: Parser<B>): Parser<B> =
    retuple(ignored(this), p) {
        it[0] as B
    }

/**
 * Creates a parser that ignores the result of the first parser and returns the result of the second parser.
 */
@JvmName("ignoredTimesParser")
operator fun <B> Parser<Unit>.times(p: Parser<B>): Parser<B> = this and p

/**
 * Creates a parser that ignores results of both parsers.
 */
@JvmName("ignoredAndIgnored")
infix fun Parser<Unit>.and(p: Parser<Unit>): Parser<Unit> =
    retuple(ignored(this), ignored(p)) {}

/**
 * Creates a parser that ignores results of both parsers.
 */
@JvmName("ignoredTimesIgnored")
operator fun Parser<Unit>.times(p: Parser<Unit>): Parser<Unit> = this and p

@JvmName("tuple2AndParser")
infix fun <T1, T2, T3> Parser<Tuple2<T1, T2>>.and(p: Parser<T3>): Parser<Tuple3<T1, T2, T3>> =
    retuple(this, p) {
        Tuple3(it[0] as T1, it[1] as T2, it[2] as T3)
    }

@JvmName("tuple2TimesParser")
operator fun <T1, T2, T3> Parser<Tuple2<T1, T2>>.times(p: Parser<T3>): Parser<Tuple3<T1, T2, T3>> =
    this and p

@JvmName("tuple2AndIgnored")
infix fun <T1, T2> Parser<Tuple2<T1, T2>>.and(p: Parser<Unit>): Parser<Tuple2<T1, T2>> =
    retuple(this, ignored(p)) {
        Tuple2(it[0] as T1, it[1] as T2)
    }

@JvmName("tuple2TimesIgnored")
operator fun <T1, T2> Parser<Tuple2<T1, T2>>.times(p: Parser<Unit>): Parser<Tuple2<T1, T2>> =
    this and p

@JvmName("tuple3AndParser")
infix fun <T1, T2, T3, T4> Parser<Tuple3<T1, T2, T3>>.and(p: Parser<T4>): Parser<Tuple4<T1, T2, T3, T4>> =
    retuple(this, p) {
        Tuple4(it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4)
    }

@JvmName("tuple3TimesParser")
operator fun <T1, T2, T3, T4> Parser<Tuple3<T1, T2, T3>>.times(p: Parser<T4>): Parser<Tuple4<T1, T2, T3, T4>> =
    this and p

@JvmName("tuple3AndIgnored")
infix fun <T1, T2, T3> Parser<Tuple3<T1, T2, T3>>.and(p: Parser<Unit>): Parser<Tuple3<T1, T2, T3>> =
    retuple(this, ignored(p)) {
        Tuple3(it[0] as T1, it[1] as T2, it[2] as T3)
    }

@JvmName("tuple3TimesIgnored")
operator fun <T1, T2, T3> Parser<Tuple3<T1, T2, T3>>.times(p: Parser<Unit>): Parser<Tuple3<T1, T2, T3>> =
    this and p

@JvmName("tuple4AndParser")
infix fun <T1, T2, T3, T4, T5> Parser<Tuple4<T1, T2, T3, T4>>.and(p: Parser<T5>): Parser<Tuple5<T1, T2, T3, T4, T5>> =
    retuple(this, p) {
        Tuple5(it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4, it[4] as T5)
    }

@JvmName("tuple4TimesParser")
operator fun <T1, T2, T3, T4, T5> Parser<Tuple4<T1, T2, T3, T4>>.times(p: Parser<T5>): Parser<Tuple5<T1, T2, T3, T4, T5>> =
    this and p

@JvmName("tuple4AndIgnored")
infix fun <T1, T2, T3, T4> Parser<Tuple4<T1, T2, T3, T4>>.and(p: Parser<Unit>): Parser<Tuple4<T1, T2, T3, T4>> =
    retuple(this, ignored(p)) {
        Tuple4(it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4)
    }

@JvmName("tuple4TimesIgnored")
operator fun <T1, T2, T3, T4> Parser<Tuple4<T1, T2, T3, T4>>.times(p: Parser<Unit>): Parser<Tuple4<T1, T2, T3, T4>> =
    this and p

@JvmName("tuple5AndParser")
infix fun <T1, T2, T3, T4, T5, T6> Parser<Tuple5<T1, T2, T3, T4, T5>>.and(p: Parser<T6>): Parser<Tuple6<T1, T2, T3, T4, T5, T6>> =
    retuple(this, p) {
        Tuple6(it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4, it[4] as T5, it[5] as T6)
    }

@JvmName("tuple5TimesParser")
operator fun <T1, T2, T3, T4, T5, T6> Parser<Tuple5<T1, T2, T3, T4, T5>>.times(p: Parser<T6>): Parser<Tuple6<T1, T2, T3, T4, T5, T6>> =
    this and p

@JvmName("tuple5AndIgnored")
infix fun <T1, T2, T3, T4, T5> Parser<Tuple5<T1, T2, T3, T4, T5>>.and(p: Parser<Unit>): Parser<Tuple5<T1, T2, T3, T4, T5>> =
    retuple(this, ignored(p)) {
        Tuple5(it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4, it[4] as T5)
    }

@JvmName("tuple5TimesIgnored")
operator fun <T1, T2, T3, T4, T5> Parser<Tuple5<T1, T2, T3, T4, T5>>.times(p: Parser<Unit>): Parser<Tuple5<T1, T2, T3, T4, T5>> =
    this and p

@JvmName("tuple6AndParser")
infix fun <T1, T2, T3, T4, T5, T6, T7> Parser<Tuple6<T1, T2, T3, T4, T5, T6>>.and(p: Parser<T7>): Parser<Tuple7<T1, T2, T3, T4, T5, T6, T7>> =
    retuple(this, p) {
        Tuple7(it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4, it[4] as T5, it[5] as T6, it[6] as T7)
    }

@JvmName("tuple6TimesParser")
operator fun <T1, T2, T3, T4, T5, T6, T7> Parser<Tuple6<T1, T2, T3, T4, T5, T6>>.times(p: Parser<T7>): Parser<Tuple7<T1, T2, T3, T4, T5, T6, T7>> =
    this and p

@JvmName("tuple6AndIgnored")
infix fun <T1, T2, T3, T4, T5, T6> Parser<Tuple6<T1, T2, T3, T4, T5, T6>>.and(p: Parser<Unit>): Parser<Tuple6<T1, T2, T3, T4, T5, T6>> =
    retuple(this, ignored(p)) {
        Tuple6(it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4, it[4] as T5, it[5] as T6)
    }

@JvmName("tuple6TimesIgnored")
operator fun <T1, T2, T3, T4, T5, T6> Parser<Tuple6<T1, T2, T3, T4, T5, T6>>.times(p: Parser<Unit>): Parser<Tuple6<T1, T2, T3, T4, T5, T6>> =
    this and p

/*
@Suppress("DeprecatedCallableAddReplaceWith", "UNUSED_PARAMETER")
@Deprecated("Further chaining with `and` is unsupported", level = DeprecationLevel.ERROR)
@JvmName("tuple7AndParser")
infix fun <T1, T2, T3, T4, T5, T6, T7, T8> Parser<Tuple7<T1, T2, T3, T4, T5, T6, T7>>.and(
    unsupported: Parser<T8>
): Nothing = error("Further chaining with `and` is unsupported")

@Suppress("DeprecatedCallableAddReplaceWith", "UNUSED_PARAMETER")
@Deprecated("Further chaining with `times` operator is unsupported", level = DeprecationLevel.ERROR)
@JvmName("tuple7TimesParser")
operator fun <T1, T2, T3, T4, T5, T6, T7, T8> Parser<Tuple7<T1, T2, T3, T4, T5, T6, T7>>.times(
    unsupported: Parser<T8>
): Nothing = error("Further chaining with `times` operator is unsupported")
*/

@JvmName("tuple7AndIgnored")
infix fun <T1, T2, T3, T4, T5, T6, T7> Parser<Tuple7<T1, T2, T3, T4, T5, T6, T7>>.and(p: Parser<Unit>): Parser<Tuple7<T1, T2, T3, T4, T5, T6, T7>> =
    retuple(this, ignored(p)) {
        Tuple7(it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4, it[4] as T5, it[5] as T6, it[6] as T7)
    }

@JvmName("tuple7TimesIgnored")
operator fun <T1, T2, T3, T4, T5, T6, T7> Parser<Tuple7<T1, T2, T3, T4, T5, T6, T7>>.times(p: Parser<Unit>): Parser<Tuple7<T1, T2, T3, T4, T5, T6, T7>> =
    this and p



@JvmName("and8")
infix fun <T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9>
        Parser<Tuple8<T1, T2, T3, T4, T5, T6, T7, T8>>.and(p: Parser<T9>):  Parser<Tuple9<T1, T2, T3, T4, T5, T6, T7, T8, T9>> =
retuple(this, p) {
    Tuple9(it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4, it[4] as T5, it[5] as T6, it[6] as T7, it[7] as T8, it[8] as T9)
}

@JvmName("and8Operator")
operator fun < T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9>
        Parser<Tuple8<T1, T2, T3, T4, T5, T6, T7, T8>>.times(p9: Parser<T9>)
        = this and p9


@JvmName("and9")
infix fun < T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9,  T10>
        Parser<Tuple9<T1, T2, T3, T4, T5, T6, T7, T8, T9>>.and(p: Parser<T10>): Parser<Tuple10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>> =
    retuple(this, p) {
    Tuple10(it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4, it[4] as T5, it[5] as T6, it[6] as T7, it[7] as T8, it[8] as T9, it[9] as T10)
}

@JvmName("and9Operator")
operator fun < T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9,  T10>
        Parser<Tuple9<T1, T2, T3, T4, T5, T6, T7, T8, T9>>.times(p10: Parser<T10>)
        = this and p10


@JvmName("and10") 
infix fun < T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9,  T10,  T11>
        Parser<Tuple10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>>.and(p: Parser<T11>):  Parser<Tuple11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>> =
    retuple(this, p) {
     Tuple11(it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4, it[4] as T5, it[5] as T6, it[6] as T7, it[7] as T8, it[8] as T9, it[9] as T10, it[10] as T11)
    }

@JvmName("and10Operator") 
operator fun < T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9,  T10,  T11>
        Parser<Tuple10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>>.times(p11: Parser<T11>)
// : AndCombinator<Tuple11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>> =
        = this and p11


@JvmName("and11")
infix fun <T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9,  T10,  T11,  T12>
        Parser<Tuple11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>>.and(p: Parser<T12>):Parser<Tuple12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>>
= retuple(this, p) {
    Tuple12(
        it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4, it[4] as T5,
        it[5] as T6, it[6] as T7, it[7] as T8, it[8] as T9, it[9] as T10,
        it[10] as T11, it[11] as T12
    )
}

@JvmName("and11Operator")
operator fun < T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9,  T10,  T11,  T12>
        Parser<Tuple11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>>.times(p12: Parser<T12>)
// : AndCombinator<Tuple12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>> =
        = this and p12


@JvmName("and12")
infix fun <T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9,  T10,  T11,  T12,  T13>
        Parser<Tuple12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>>.and(p13: Parser<T13>):  Parser<Tuple13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>> =
retuple(this, p13) {
    Tuple13(it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4, it[4] as T5, it[5] as T6, it[6] as T7, it[7] as T8, it[8] as T9, it[9] as T10, it[10] as T11, it[11] as T12, it[12] as T13)
}

@JvmName("and12Operator")
operator fun < T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9,  T10,  T11,  T12,  T13>
        Parser<Tuple12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>>.times(p13: Parser<T13>)
       = this and p13


@JvmName("and13")
infix fun < T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9,  T10,  T11,  T12,  T13,  T14>
        Parser<Tuple13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>>.and(p14: Parser<T14>):  Parser<Tuple14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>> =
retuple(this, p14) {
    Tuple14(it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4, it[4] as T5, it[5] as T6, it[6] as T7, it[7] as T8, it[8] as T9, it[9] as T10, it[10] as T11, it[11] as T12, it[12] as T13, it[13] as T14)
}

@JvmName("and13Operator")
operator fun < T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9,  T10,  T11,  T12,  T13,  T14>
        Parser<Tuple13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>>.times(p14: Parser<T14>)
       = this and p14


@JvmName("and14")
infix fun < T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9,  T10,  T11,  T12,  T13,  T14,  T15>
        Parser<Tuple14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>>.and(p15: Parser<T15>) :  Parser<Tuple15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>> =
retuple(this, p15) {
    Tuple15(it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4, it[4] as T5, it[5] as T6, it[6] as T7, it[7] as T8, it[8] as T9, it[9] as T10, it[10] as T11, it[11] as T12, it[12] as T13, it[13] as T14, it[14] as T15)
}

@JvmName("and14Operator")
operator fun < T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9,  T10,  T11,  T12,  T13,  T14,  T15>
        Parser<Tuple14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>>.times(p15: Parser<T15>)
        = this and p15


@JvmName("and15")   infix fun < T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9,  T10,  T11,  T12,  T13,  T14,  T15,  T16>
        Parser<Tuple15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>>.and(p16: Parser<T16>):  Parser<Tuple16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>>
= retuple(this, p16) {
    Tuple16(
        it[0] as T1, it[1] as T2, it[2] as T3, it[3] as T4, it[4] as T5,
        it[5] as T6, it[6] as T7, it[7] as T8, it[8] as T9, it[9] as T10,
        it[10] as T11, it[11] as T12, it[12] as T13, it[13] as T14, it[14] as T15,
        it[15] as T16
    )
}

@JvmName("and15Operator")
operator fun < T1,  T2,  T3,  T4,  T5,  T6,  T7,  T8,  T9,  T10,  T11,  T12,  T13,  T14,  T15,  T16>
        Parser<Tuple15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>>.times(p16: Parser<T16>)
        = this and p16

